/* 
 * 青莲云和TCU的接口 
 * 
 * 
 */

#include "interface_ql.h"
#include <dlfcn.h>
#include "tools.h"
#include "app_debug_main.h"
#include "meter_ql.h"
#include "program.h"
#include "rd_interface.h"
#include "log_main.h"
#include "ffs.h"
#include "database.h"

#ifdef  QL_CLOUD_CLIENT

ql_para_form_main  para_ql; // 青莲云参数配置 

callbackFun main_update_bms = NULL;     // 更新BMS信息 

Charge_Arg g_charge_arg[GUN_NUM];   // 充电信息 

xj_price_model  charge_model;   // 充电费率配置信息 

void* p = (void*)&para_ql;      // 青莲云参数 

extern tran_record_xj  cur_record[GUN_NUM];
// APP 远程开启充电 
int startCharge_ql(u8 gunid , void* para)
{
    int ret = -1;
    Charge_Arg *pChargeArg = (Charge_Arg*)para; // 充电信息 
    TDateTime datetime;

    gunid = (u8)pChargeArg->guntab;     // 充电枪 
    read_current_datetime(&datetime);   // 获取时间 

    g_ifApp[gunid] = _APP_MODE_;
    g_uidata->cmd3[gunid].state = _APP_MODE_;
    g_sss[gunid] = 0;       // 界面状态刷新计时清零 

    g_uidata->cmd2[gunid].result = 0;   // 开始充电结果 

    if (getChargeState(gunid) != 0) // 充电枪正在充电 
    {
        ui_debug("桩正在充电！！！！！");
		ret = CHARGE_STATE_ERR;
    }
    else
    {
        datarecording(gunid, 1);    // 计算当前充电花费 
		ret = TCUStartChargeProcess(gunid, 0);  // 
    }

    if (ret == 0)   // 成功开启充电枪 
    {
        g_charge_arg[gunid] = *(Charge_Arg*)p;
        g_stop_reason[gunid] = 0;
        g_uidata->cmd3[gunid].guntab = gunid;
        memset(g_uidata->cmd3[gunid].stopcode, 0x39, 6); // "99999"
        g_uidata->cmd3[gunid].stopcode[6] = 0x00;
        g_uidata->cmd2[gunid].available_money = 100000; // 默认账户余额

		g_uidata->cmd3[gunid].state = 1;    // APP充电 
        ui_debug("远程启动时app充电交易流水号=%s  gunid=%d", g_charge_arg[gunid].serialnum, gunid);
		ui_debug("远程启动时app停止密码=%s ", g_uidata->cmd3[gunid].stopcode);
    }
    else
    {
        g_stop_reason[gunid] = ret;
        ui_debug("接收到远程发来的充电要求,但充电失败！！！");
		if (gm_sys_state[gunid] == _SYS_START_FIN_) {
			ui_debug("正在充电，接收到远程发来的充电要求,充电失败！！！");
			return 408;
		}
        g_charge_arg[gunid] = *(Charge_Arg*)p;
		g_uidata->cmd2[gunid].fail_Reason = ret;
		g_uidata->gunmsg[gunid].charge_state = 0;
		//g_stop_reason[gunid] = 5;
		//g_stop_detail[gunid] = ret;
		g_ifApp[gunid] = _IDEL_MODE_APP_;
    }

    return ret;
}

// APP 远程停止充电 
int stopCharge_ql(u8 gunid ,void* para)
{
    
	//粤易充		   1.本地刷卡终止，2.远程终止充电，3充满自动停止，4余额不足，5充电桩故障，6 BMS故障，7、急停按钮停止，
				//8.验证码停止，9.停电结束，10.按电量满足结束，11.按金额满足结束，12.按时间满足结束，13.拔枪结束，
	//羊城充			1本地刷卡终止，2远程终止充电，3充满自动停止，4余额不足，5充电桩故障，6 BMS故障   	7、急停按钮停止
				//8充电时间到自动停止 9充电金额到自动停止 10充电电量到自动停止
	int ret=0;
	u8  stop_reason = 2;
    
	debug_104("接收到主站发来的充电停止要求 gunid=%d",gunid);
    
	if (gm_sys_state[gunid] ==_SYS_WAIT_CHARGING_START_)
	{
		
	}

	if (para != NULL)
	{
		stop_reason = *(u8*)para;
	}
	// 调用硬件接口，停止充电 
	ret = TCUStopChargeProcess(gunid, stop_reason);

    return ret;
}

int tcu_adjust_charge_pw(u8 gunid,u8 type,int value)
{
	int ret;
    printf("tcu_adjust_charge_pw  value=%d\r\n",value);
//	value/=10;

	ret = orderFormOther(gunid,type,value, 3600, NULL);//&bak_ctrl_pw);


//	ret=can_adjust_charge_pw(gunid,type,value);
    printf("1tcu_adjust_charge_pw value=%d\r\n",value);
	return ret;
}


int tcu_unlock_op(u8 gunid, u8 value)
{
    if (value > 0)
    {
        value = 2;
    }
    else
    {
        value = 1;
    }

	return orderFormOther(gunid, 100, value, 1000, NULL);//&bak_ctrl_pw);
}

void update_charge_fee(ql_fee_config* p_fee)
{
    for (int i = 0; i < GUN_NUM; i++)
    {
        g_charge_arg[i].fee_config = *p_fee;
    }
}

int callbackFunMain(cmdlist *cmd)
{
    int ret = 0;
	t_operate_reason*  p_op_reason = NULL;

    if (!cmd)
    {
		return -1;
    }

    switch (cmd->cmdtype)
    {
    case RENEW_NET_FLAG:
        {
            if(cmd->body == (void*)0)
                g_uidata->net_state = 0;
            else
                g_uidata->net_state = 1;
            printf("\r\n网络连接发生变化  flag=%d \r\n",g_uidata->net_state);

        }
        break;

    case SET_1ST_QRCODE:
        {
            char* qrcode=(char *)cmd->body;
            g_uidata->cmd6[0].req_state=1;
            g_uidata->cmd6[0].guntab=0;
            SaveQRCode(0,qrcode);
            sprintf(g_uidata->cmd6[0].qrCode, "%s",qrcode );
        }
        break;

    case SET_2ND_QRCODE:
        {
            char* qrcode=(char *)cmd->body;
    		g_uidata->cmd6[1].req_state=1;
    		g_uidata->cmd6[1].guntab=1;
    		SaveQRCode(1,qrcode);
    		sprintf(g_uidata->cmd6[1].qrCode, "%s",qrcode );
        }
        break;

    case READ_CHARGE_RECORD:
        {
            int ret=1;
      	    int i;
            
    	    tran_record_ql  *pecord=(tran_record_ql  *)cmd->body;
      	    for(i = 0; i < 3; i++)
      	    {

    	        ret = protocol_get_offlineCD(pecord);
    	        if(ret == 0)
    	        {
    	        	ui_debug("查找离线数据 precord->flag_finished=%d  交易流水号=%s",pecord->flag_finished,pecord->serialnum);
    	        	break;
    	        }
    	        else
    	        {
    	        	ui_debug("查找离线数据 无");
    	        }
      	    }
            return ret;
        }
        break;

    case FIN_CHARGE_RECORD:
        {
            ret=-1;
    	    tran_record_xj  *precord=(tran_record_xj  *)cmd->body;
    	    protocol_getCD_bySerialnum(precord);

    		precord->flag_finished = 0xaa;
    	    ret = protocol_updateCD(precord);
    	    sleep(1);
    	    if (ret != 0)
    	    {
    	    	ret=1;
    	    	debug_104("写入数据库出错！！！！！");
    	    }
    	    else
    	    {
    	    	ret=0;
    	    	debug_104("写入数据库成功！！！！！");
    	    }
    		return ret;
        }
        break;

    case UPDATA_FILES:
        {
            if(cmd->body==(void*)0)
                g_uidata->update_state=0;
            else
                g_uidata->update_state=1;
            ui_debug("是否远程升级  flag=%d",g_uidata->update_state);
        }
        break;

    case SET_STOP_DETAIL_REASON:	// 2021-07-04
    	{
    		p_op_reason = (t_operate_reason*)cmd->body;
    		if ((p_op_reason != NULL) && (p_op_reason->gun_id < 8))	//  参数有效性检查
    		{
				g_stop_reason[p_op_reason->gun_id] = p_op_reason->reason;	// 类型
				g_stop_detail[p_op_reason->gun_id] = p_op_reason->detail_code;	// 故障码 
				g_uidata->gunmsg[p_op_reason->gun_id].stopreason = g_stop_reason[p_op_reason->gun_id];
				g_uidata->gunmsg[p_op_reason->gun_id].m_stopReason = g_stop_detail[p_op_reason->gun_id];
    		}
    	}
    	break;
	
    case SAVE_FEE_CFG:
        {   
            if(cmd->body==(void*)0)
            {
                //g_uidata->update_state=0;
            }
            else
            {
                int i;
                ql_para_form_main* p_xj = (ql_para_form_main*)cmd->body;
                for(i=0;i<48;i++)
                {
                    charge_model.power_rate[i] = p_xj->fee_config.charge_fee[i]*100;
                    charge_model.service_rate[i] = p_xj->fee_config.service_fee[i]*100;
                }
                update_charge_fee(&p_xj->fee_config);
                protocol_update_PriceModel(&charge_model);
                ui_debug("收到平台要求设在费率模型 保存到数据库");
            }
        }
        break;
    
    case SAVE_CHARGE_RECORD:
        {
            tran_record_xj  *precord=(tran_record_xj  *)cmd->body;
            u8 gunid=precord->guntab;
            SavechargeRecord(gunid, 2, g_stop_reason[gunid]);
            g_uidata->gunmsg[gunid].stopreason=g_stop_reason[gunid];
    
            printf("充电结束保存充电记录！！！ g_stop_reason[%d]=%d\r\n",gunid,g_stop_reason[gunid]);
            debug_104("本次订单号 %.*a   cur_record[%d]=%.*a",16,precord->serialnum,gunid,16, cur_record[gunid].serialnum);
            debug_104("本次订单 rd.flag_finished=%x 开始时间 %.*a    cur_record[gunid].end_soc=%d",precord->flag_finished,7,precord->starttime,cur_record[gunid].end_soc);
            *precord = cur_record[gunid];
    
            ret=0;
        }
        break;

    case SET_BILL:
		{
			 MeterData_ql*  ql_meter_data;
			 int gunid;
			 if(cmd->body != (void*)0)
			 {
				 ql_meter_data = (MeterData_ql*)cmd->body;
				 gunid = ql_meter_data->gun_id;
				 g_uidata->gunmsg[gunid].cost_elec = (ql_meter_data->cost_elec + 5000) / 10000;	// 10000 * 100, 电量（10000） × 费率（100）
				 g_uidata->gunmsg[gunid].cost_server = (ql_meter_data->cost_server + 5000) / 10000;
				 g_uidata->gunmsg[gunid].curcostmoney = (g_uidata->gunmsg[gunid].cost_elec + g_uidata->gunmsg[gunid].cost_server);
				 g_uidata->gunmsg[gunid].charge_duration = ql_meter_data->charge_duration;  // 分钟
				 g_uidata->gunmsg[gunid].curkWh = ql_meter_data->curkWh[0] / 10;	// 10000 放大1000倍
				 //2021-06-18
				 g_uidata->gunmsg[gunid].rate = ql_meter_data->cur_elec*100;
				 g_uidata->gunmsg[gunid].rate_server = ql_meter_data->cur_servicer*100;
				 // update bill
				 g_uidata->gunmsg[gunid].charge_state = 4; //4 表示充电结束
				 g_uidata->cmd4[gunid].result=0;//发起充电时由UI写入0,由主控写入命令返回结果1成功2失败
			 }
		}
    	break;

    case GET_CAM_METER_ST:
    	if (cmd->body != (void*)0)
    	{
    		DevCom_ql *p_data = (DevCom_ql*)cmd->body;
    		u8 gunid = p_data->gun_id;
    		p_data->can_comm = (g_candata.errcode[gunid]) ? (1) : (0);
    		p_data->meter_comm = (g_realData[gunid].failReadMt) ? (1) : (0);
    	}
    	break;

    default:
        break;
    }

    return ret;
}

// 更新BMS配置信息 
int update_Bms(u8 gunid,void* pdata)
{
    ui_debug("收到来自CAN的BMS数据！！！！");
    
    if(main_update_bms != NULL)
    {
        main_update_bms(gunid, pdata);
    }

    return 0;
}

void QLcloudInit(pconf conf)
{
    int  i;
    void *handle;
    char *error;
    init_ql_fun func = NULL;

    printf(" ------ QLcloud Client ------ \r\n");
    printf(" ---------- qlcloud conf.gunnum = %d \r\n", conf.gunnum);

    for (i = 0; i < conf.gunnum; i++)
    {
        initRdMem(i);   // 
    }
    
    para_ql.type = conf.devtype;    // AC,DC 
    para_ql.gunnum = conf.gunnum;   // 充电枪数量 
    
    para_ql.server_port = conf.server_port;
    memcpy(para_ql.server_ip, conf.server_ip, 32);
    
    memcpy(para_ql.devNo, conf.devNO, strlen(conf.devNO));    // 设备号 
	for (i = 0; i < 32; i++)
	{
		if(para_ql.devNo[i]==0x0d || para_ql.devNo[i]==0x0a)
			para_ql.devNo[i]=0x00;
	}
    debug_104("初始化时候的充电桩号=%.*a 编号长度=%d", 32, para_ql.devNo, strlen(para_ql.devNo));
    para_ql.charge_mode_num  = 4;
    
    para_ql.max_v   = conf.MaxV;
    para_ql.max_i   = conf.MaxI;
    para_ql.max_power = 1600;
    para_ql.min_power = 1000;

    para_ql.rated_i = 30;
    para_ql.rated_v = 2200;
    para_ql.rated_power = 700;
	para_ql.charge_mode_rate = 1200; // 120.0kW 
	
    memcpy(para_ql.interface_id, conf.interface_id, strlen(conf.interface_id));    // 接口ID 
    memcpy(para_ql.token, conf.token, strlen(conf.token));    // 接人token 
    
    handle = dlopen(LIB_QL_PATH, RTLD_LAZY);
    if (!handle) {
        fprintf(stderr, "%s\n", dlerror());
        exit(EXIT_FAILURE);
    }
    dlerror();

    *(void **) (&func) = dlsym(handle, "initQlCloud");
    if ((error = dlerror()) != NULL) {
		fprintf(stderr, "%s\n", error);
		exit(EXIT_FAILURE);
	}

    *(void **) (&main_updateYX) = dlsym(handle, "QL_updateYX");
	if ((error = dlerror()) != NULL) {
		fprintf(stderr, "%s\n", error);
		exit(EXIT_FAILURE);
	}

    *(void **) (&main_updateYC) = dlsym(handle, "QL_updateYC");
	if ((error = dlerror()) != NULL) {
		fprintf(stderr, "%s\n", error);
		exit(EXIT_FAILURE);
	}
    
	*(void **) (&main_updateMtData) = dlsym(handle, "QL_updateMtData");
	if ((error = dlerror()) != NULL) {
		fprintf(stderr, "%s\n", error);
		exit(EXIT_FAILURE);
	}

    *(void **) (&main_updateMtDataReal) = dlsym(handle, "QL_updateMtDataReal");
	if ((error = dlerror()) != NULL) {
		fprintf(stderr, "%s\n", error);
		exit(EXIT_FAILURE);
	}

	*(void **) (&main_FinStartCharge) = dlsym(handle, "QL_finStartCharge");
	if ((error = dlerror()) != NULL) {
	    printf("QL_finStartCharge 失败！！！！！！！！！！！！\n");
		fprintf(stderr, "%s\n", error);
		exit(EXIT_FAILURE);
	}
	else
	{
		printf("QL_FinStartCharge 成功！！！！！！！！！！！！\n");
	}

    
    *(void **) (&main_FinStopCharge) = dlsym(handle, "QL_finStopCharge");
    if ((error = dlerror()) != NULL) {
        printf("QL_finStopCharge 失败！！！！！！！！！！！！\n");
        fprintf(stderr, "%s\n", error);
        exit(EXIT_FAILURE);
    }
    else
    {
        printf("QL_FinStopCharge 成功！！！！！！！！！！！！\n");
    }

    para_ql.startCharge = startCharge_ql;
	para_ql.stopCharge  = stopCharge_ql;
	para_ql.cmd_fun     = callbackFunMain;
    para_ql.adjust_charge_pw = tcu_adjust_charge_pw;
    para_ql.unlock_func = tcu_unlock_op;
    
	protocol_get_PriceModel(&charge_model);

    for (i = 0; i < 48; i++)
	{
		para_ql.fee_config.charge_fee[i]  = charge_model.power_rate[i]/100;
		para_ql.fee_config.service_fee[i] = charge_model.service_rate[i]/100;
		para_ql.fee_config.belate_fee[i]  = 100;
	}
	para_ql.writelog=fs_debug_104;

    func(p);
    
}


int initQRCode(u8 gunid )
{
	int count;
	int start;
	int fid;
	int i;
	char devNo[32];
    
	fid   = FILE_ID_QRCODE;
	start = QRCODE_START + gunid*QRCODESIZE;
    
	count = app_fs_read(fid, start, QRCODESIZE, (u8*) g_uidata->cmd6[gunid].qrCode);
    if (count == 0) 
    {
    	memcpy(devNo,pconfig->devNO,strlen(pconfig->devNO));
    	for(i=0;i<32;i++)
    	{
    		if(devNo[i]==0x0d ||devNo[i]==0x0a)
    			devNo[i]=0x00;
    	}
    	printf("设置号枪=%d！！！！！！！！！！！！！！！！！！\r\n",gunid);

    	sprintf(g_uidata->cmd6[gunid].qrCode, "hlht://%s0%d.101437000/",devNo,gunid+1);

    	printf("得到的二维编码=%s",g_uidata->cmd6[gunid].qrCode);
    	count = app_fs_write(fid, start, QRCODESIZE, (u8*) g_uidata->cmd6[gunid].qrCode);
    }
    
	return 0;

}

void SaveQRCode(u8 gunid, char*rdcode )
{
    int start;
	int fid;

	fid=FILE_ID_QRCODE;
	if(gunid==1)
	{
		start = QRCODE_START+QRCODESIZE;
	}
	else
	{
		start=QRCODE_START;
	}

    // 更新二维码显示内容 
    strncpy(g_uidata->cmd6[gunid].qrCode, rdcode, QRCODESIZE);
    
    app_fs_write(fid, start, QRCODESIZE, (u8*)rdcode);

}



#endif 

